package com.xjj.core.modules.commons.utils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;


import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;


public class MyBeanUtils {
	
	protected static Logger logger = LoggerFactory.getLogger(MyBeanUtils.class);

	/**
	 * 获得同时有get和set的field和value。
	 * 
	 * @param bean
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static Map describe(Object bean) {
		Map des = new HashMap();
		PropertyDescriptor desor[] = PropertyUtils.getPropertyDescriptors(bean);
		String name = null;
		for (int i = 0; i < desor.length; i++) {
			if (desor[i].getReadMethod() != null
					&& desor[i].getWriteMethod() != null) {
				name = desor[i].getName();
				try {
					des.put(name, PropertyUtils.getProperty(bean, name));
				} catch (Exception e) {
					throw new RuntimeException("属性不存在：" + name);
				}
			}
		}
		return des;
	}

	public static void setSimpleProperty(Object bean, String name, Object value) {
		try {
			PropertyUtils.setSimpleProperty(bean, name, value);
		} catch (Exception e) {
			throw new RuntimeException("属性不存在：" + name);
		}
	}

	public static Object setSimpleProperty(Object bean, String name) {
		try {
			return PropertyUtils.getSimpleProperty(bean, name);
		} catch (Exception e) {
			throw new RuntimeException("属性不存在：" + name);
		}
	}

	/**
	 * 直接读取对象属性值,无视private/protected修饰符,不经过getter函数.
	 */
	public static Object getFieldValue(Object object, String fieldName)
			throws NoSuchFieldException {
		Field field = getDeclaredField(object, fieldName);
		if (!field.isAccessible()) {
			field.setAccessible(true);
		}

		Object result = null;
		try {
			result = field.get(object);
		} catch (IllegalAccessException e) {
			logger.error("不可能抛出的异常{}", e.getMessage());
		}
		return result;
	}

	/**
	 * 直接设置对象属性值,无视private/protected修饰符,不经过setter函数.
	 */
	public static void setFieldValue(Object object, String fieldName,
			Object value) throws NoSuchFieldException {
		Field field = getDeclaredField(object, fieldName);
		if (!field.isAccessible()) {
			field.setAccessible(true);
		}
		try {
			field.set(object, value);
		} catch (IllegalAccessException e) {
			logger.error("不可能抛出的异常:{}", e.getMessage());
		}
	}

	/**
	 * 循环向上转型,获取对象的DeclaredField.
	 */
	public static Field getDeclaredField(Object object, String fieldName)
			throws NoSuchFieldException {
		Assert.notNull(object);
		return getDeclaredField(object.getClass(), fieldName);
	}
	
	//--------------------下面的来自JsonConvert----网友指导----------------------------------------------
	//net.gbicc.x27.util.hibernate.ModelUtils
	/**
	 * 循环向上转型,获取类的DeclaredField.
	 */
	@SuppressWarnings("unchecked")
	public static Field getDeclaredField(Class clazz, String fieldName)
			throws NoSuchFieldException {
		Assert.notNull(clazz);
		Assert.hasText(fieldName);
		for (Class superClass = clazz; superClass != Object.class; superClass = superClass
				.getSuperclass()) {
			try {
				return superClass.getDeclaredField(fieldName);
			} catch (NoSuchFieldException e) {
				// Field不在当前类定义,继续向上转型
			}
		}
		throw new NoSuchFieldException("No such field: " + clazz.getName()
				+ '.' + fieldName);
	}
	
	/**暴力获取对象变量值,忽略private,protected修饰符的限制.
     * @param obj Object
     * @param propertyName String
     * @return getObject
	 * @throws NoSuchFieldException 
     */
    public static Object forceGetProperty(Object obj, String propertyName) throws Exception {
        Assert.notNull(obj);
        Assert.hasText(propertyName);
        Field field = getDeclaredField(obj, propertyName);
        boolean accessible = field.isAccessible();
        field.setAccessible(true);
        Object result = getFieldValue(obj, field);
        field.setAccessible(accessible);
        return result;
    }

    /**暴力设置对象变量值,忽略private,protected修饰符的限制
     * @param object Object
     * @param propertyName String
     * @param value Object
     */
    public static void forceSetProperty(Object object, String propertyName, Object value)throws Exception {
        Assert.notNull(object);
        Assert.hasText(propertyName);
        Field field = getDeclaredField(object, propertyName);
        boolean accessible = field.isAccessible();
        field.setAccessible(true);
        setFieldValue(object, field, value);
        field.setAccessible(accessible);
    }
    
    /**转换非RuntimeException
     * @param obj Object
     * @param field Field
     * @return Object 
     * @see java.lang.Field#get(Object)
     */
    public static Object getFieldValue(Object obj, Field field) {
        Assert.notNull(obj);
        Assert.notNull(field);
        try {
            return field.get(obj);
        } catch (IllegalAccessException ex) {
            ex.printStackTrace();
            throw new IllegalArgumentException(ex.getMessage());
        }
    }

    /**转换非RuntimeException
     * @param obj Object
     * @param field Field
     * @return Object 
     * @see java.lang.Field#get(Object)
     */
    public static void setFieldValue(Object obj, Field field, Object value) {
        Assert.notNull(obj);
        Assert.notNull(field);
        try {
            field.set(obj, value);
        } catch (IllegalAccessException ex) {
            ReflectionUtils.handleReflectionException(ex);
        }
    }

    /**转换非RuntimeException
     * @param bean Object
     * @param name String
     * @return Object
     * @see org.apache.commons.beanutils.PropertyUtils#getProperty(Object, String)
     */
    public static Object getProperty(Object bean, String name) {
        try {
            return PropertyUtils.getProperty(bean, name);
        } catch (IllegalAccessException ex) {
            ex.printStackTrace();
            throw new IllegalArgumentException(ex.getMessage());
        } catch (InvocationTargetException ex) {
            ex.printStackTrace();
            throw new IllegalArgumentException(ex.getMessage());
        } catch (NoSuchMethodException ex) {
            ex.printStackTrace();
            throw new IllegalArgumentException(ex.getMessage());
        }
    }
    
    /**转换非RuntimeException
     * @param bean Object
     * @param name String
     * @param value Object
     * @see org.apache.commons.beanutils.PropertyUtils#setProperty(Object, String, Object)
     */
    public static void setProperty(Object bean, String name, Object value) {
        try {
            PropertyUtils.setProperty(bean, name, value);
        } catch (IllegalAccessException ex) {
            ReflectionUtils.handleReflectionException(ex);
        } catch (InvocationTargetException ex) {
            ReflectionUtils.handleReflectionException(ex);
        } catch (NoSuchMethodException ex) {
            ReflectionUtils.handleReflectionException(ex);
        }
    }
    
    /**解析json字符串成JSONObject，JSONObject中的data数据再解析成JSONArray
     * 处理JSONArray中的JSONObject
     * 根据JSONObject中的键值对应关系，复制到obj中相应的setMethod中。
     * @param jsonStr jsonStr
     * @param cls class
     */
    public static List convertObj(String jsonStr, Class cls) {
        JSONObject jsonObj = JSONObject.fromObject(jsonStr);
        return convertObj(jsonObj.getJSONArray("data"), cls);
    }
    
    /**
     * 处理JSONArray中的JSONObject
     * 根据JSONObject中的键值对应关系，复制到obj中相应的setMethod中。
     * @param jsonArray JSONArray
     * @param cls class
     */
    public static List convertObj(JSONArray jsonArray, Class cls) {
        List list = new ArrayList();
    	for (int i=0;i<jsonArray.size();i++){
			JSONObject obj_JS = jsonArray.getJSONObject(i);
			list.add(convertObj(obj_JS, cls));
    	}
      /*  for (Iterator iterator = jsonArray.iterator(); iterator.hasNext();) {
            JSONObject jsonObj = (JSONObject) iterator.next();
            list.add(convertObj(jsonObj, cls));
        }*/
        return list;
    }
    
    /**
     * 根据JSONObject中的键值对应关系，复制到obj中相应的setMethod中。
     * @param cls class
     * @param cls class
     */
    public static Object convertObj(JSONObject jsonObj, Class cls) {
        Object obj = createInstance(cls);
        convertObj(jsonObj, obj);
        return obj;
    }
    
    /**
     * 根据JSONObject中的键值对应关系，复制到obj中相应的setMethod中。
     * @param jsonObj JSONObject
     * @param obj 需要赋值的临时对象
     * 要进行id -- Long 型处理
     * 还有进行时间类型处理----------这个方法要进行修改，才能符合大部分需求，long，date ,set，list等
     * 
     * 希望关联就不需要进行处理，只是处理id值更好---------考虑怎样去实现
     * 
     * 
     */
    public static void convertObj(JSONObject jsonObj, Object obj) {
		PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(obj
				.getClass());
		for (int i = 0; i < pds.length; i++) {
			PropertyDescriptor pd = pds[i];
			if (jsonObj.containsKey(pd.getName())
					&& (pd.getPropertyType() == String.class
							|| pd.getPropertyType() == Integer.class
							|| pd.getPropertyType() == Date.class || pd
							.getPropertyType() == Long.class)) {
				Long longs = null;
				if (pd.getName().equals("id")) {
					Object param = jsonObj.get(pd.getName());
					if (param instanceof Integer) {
						logger.info("Integer---处理----- ");
						logger.info("Integer---处理----- "+pd.getName());
						int value = ((Integer) param).intValue();
						longs = new Long(value);

					} else if (param instanceof String) {
						logger.info("String-------- ");
						String s = (String) param;
						try {
							longs = Long.parseLong(s);
						} catch (Exception e) {
							// TODO: handle exception
						}
					} else if (param instanceof Double) {
						//double d = ((Double) param).doubleValue();
						logger.info("Double-------- ");
					} else if (param instanceof Float) {
						//float f = ((Float) param).floatValue();
						logger.info("Float-------- ");
					} else if (param instanceof Long) {
						//long l = ((Long) param).longValue();
						logger.info("Long-------- ");
					} else if (param instanceof Boolean) {
						//boolean b = ((Boolean) param).booleanValue();
						logger.info("Boolean-------- ");
					} else if (param instanceof Date) {
						//Date d = (Date) param;
						logger.info("Date-------- ");
					}
					invokeSetMethod(obj, pd.getWriteMethod(), longs);
				} else if (pd.getPropertyType() == Date.class) {
					logger.info("时间处理。。。。。 ");
				} else {
					// logger.info("字符串处理。。。。。 ");
					invokeSetMethod(obj, pd.getWriteMethod(), jsonObj.get(pd
							.getName()));
				}
			}
		}
	}

    
    
    
    
    public static Object createInstance(Class cls) {
        try {
            return cls.newInstance();
        } catch (InstantiationException ex) {
            ex.printStackTrace();
            throw new IllegalArgumentException(ex.getMessage());
        } catch (IllegalAccessException ex) {
            ex.printStackTrace();
            throw new IllegalArgumentException(ex.getMessage());
        }
    }
    
    /**
     * 把对象中所有null属性并且类型为String的赋值""，确保非空。
     * @param obj
     */
    public static void setValueWithoutNull(Object obj) {
        if(obj == null) {
            return;
        }
        PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(obj.getClass());
        for (int i = 0; i < pds.length; i++) {
            PropertyDescriptor pd = pds[i];
            Object getObj = invokeGetMethod(obj, pd.getReadMethod());
            if (getObj == null && pd.getPropertyType() == String.class) {
                invokeSetMethod(obj, pd.getWriteMethod(), "");
            }
        }
    }
    
    public static boolean equals(Object x, Object y) {
        return x == y || (x != null && y != null && x.equals(y));
    }

    /**
     * 把source对象中非空的值COPY到target中
     * ModelUtils.transferValue(source, target);
     * @param source
     * @param target
     */
    public static void transferValue(Object source, Object target) {
        if (source == target) {
            return;
        }
        Method[] methodsOld = source.getClass().getMethods();
        Method[] methodsNew = target.getClass().getMethods();
        for (int i = 0; i < methodsOld.length; i++) {
            if (!methodsOld[i].getName().startsWith("get")) {
                continue;
            }
            //suffix of methodName
            String suffix = methodsOld[i].getName().substring(3);
            for (int j = 0; j < methodsNew.length; j++) {
                if (!methodsNew[j].getName().equals("set" + suffix)) {
                    continue;
                }
                if (!isGetMethod(methodsOld[i]) || !isSetMethod(methodsNew[j])
                /*get的返回类型要和SET的参数类型一致*/
                 || methodsNew[j].getParameterTypes()[0] != methodsOld[i].getReturnType()
                 ) {
                    continue;
                }
                
                Object getObj = invokeGetMethod(source, methodsOld[i]);
                if (getObj != null) {
                    invokeSetMethod(target, methodsNew[j], getObj);
                }
                break;
            }
        }
    }
    
    /**
     * get没有参数，get方法是public的
     * @param method
     * @return
     */
    public static boolean isGetMethod(Method method) {
        if (method == null) {
            return false;
        }
        if (!method.getName().startsWith("get")) {
            return false;
        }
        if (method.getParameterTypes().length > 0) {
            return false;
        }
        if (!Modifier.isPublic(method.getModifiers())) {
            return false;
        }
        return true;
    }
    
    /**
     * set的参数必须只有一个，set的返回类型为void，set方法是public的
     * @param method
     * @return
     */
    public static boolean isSetMethod(Method method) {
        if (method == null) {
            return false;
        }
        if (!method.getName().startsWith("set")) {
            return false;
        }
        if (method.getParameterTypes().length != 1) {
            return false;
        }
        if (method.getReturnType() != Void.TYPE) {
            return false;
        }
        if (!Modifier.isPublic(method.getModifiers())) {
            return false;
        }
        return true;
    }
    
    /**
     * 调用get方法，转换非RuntimeException
     * @param object
     * @param method
     * @return
     */
    public static Object invokeGetMethod(Object object, Method method) {
        try {
            return method.invoke(object, new Object[0]);
        } catch (IllegalAccessException ex) {
            ex.printStackTrace();
            throw new IllegalArgumentException(ex.getMessage());
        } catch (InvocationTargetException ex) {
            ex.printStackTrace();
            throw new IllegalArgumentException(ex.getMessage());
        }
    }
    
    /**
     * 调用set方法，转换非RuntimeException
     * @param object
     * @param method
     * @return
     */
    public static void invokeSetMethod(Object object, Method method, Object value) {
        try {
        	if(method!=null){
        		 method.invoke(object, new Object[] {value});
        	}
        } catch (IllegalAccessException ex) {
            ex.printStackTrace();
            throw new IllegalArgumentException(ex.getMessage());
        } catch (InvocationTargetException ex) {
            ex.printStackTrace();
            throw new IllegalArgumentException(ex.getMessage());
        }
    }
    
    /**
     * 获得某个对象中一个指定方法名的方法对象，转换非RuntimeException
     * @param Class 指定对象类型
     * @param methodName 方法名
     * @param parameterTypes 方法参数类型数组
     * @return 方法对象
     */
    public static Method getMethod(Class clazz, String methodName, Class[] parameterTypes) {
        try {
            return clazz.getMethod(methodName, parameterTypes);
        } catch (SecurityException ex) {
            ex.printStackTrace();
            throw new IllegalArgumentException(ex.getMessage());
        } catch (NoSuchMethodException ex) {
            ex.printStackTrace();
            throw new IllegalArgumentException(ex.getMessage());
        }
    }
    
    /**
     * 把一个List<model>变成一个Map，map中的key是指定的名称，
     * 原始List中model.getKeyName相等的都归为一类放到map中key对应的list中
     * @param models List<model>
     * @param keyName 指定的归类名称
     * @return Map<String, List<model>>
     */
    public static Map list2MapWithListValue(Collection models, String keyName) {
        if (keyName == null || keyName.length() < 2) {
            throw new IllegalArgumentException("invalid keyName:" + keyName);
        }
        String methodName = "get" + keyName.substring(0, 1).toUpperCase() + keyName.substring(1);
        Map map = new HashMap();
        for (Iterator iter = models.iterator(); iter.hasNext();) {
            Object element = (Object) iter.next();
            Method getMethod = getMethod(element.getClass(), methodName, new Class[0]);
            Object getObj = invokeGetMethod(element, getMethod);
            String key = getObj == null ? null : getObj.toString();
            List subList = (List) map.get(key);
            if (subList == null) {
                subList = new LinkedList();
                map.put(key, subList);
            }
            subList.add(element);
        }
        return map;
    }
    
    /**
     * 根据一个方法名，得到它的属性名，方法只有两种get方法和set方法，属性名第一个强制变小写
     * @param methodName
     * @return
     */
    public static String getPropertyName(String methodName) {
    	//logger.info("根据一个方法名，得到它的属性名，方法只有两种get方法和set方法，属性名第一个强制变小写....");
        return methodName.substring(3, 4).toLowerCase() + methodName.substring(4);
    }
    
    /**
     * 根据一个属性名，得到它的get方法名
     * @param propertyName
     * @return
     */
    public static String getGetMehodName(String propertyName) {
    	//logger.info("根据一个属性名，得到它的get方法名,将首字母大写....");
    	//将首字母大写
        return "get" + StringUtils.capitalize(propertyName);
    }
    
    /**
     * 根据一个属性名，得到它的set方法名
     * @param propertyName
     * @return
     */
    public static String getSetMehodName(String propertyName) {
    	//logger.info("根据一个属性名，得到它的set方法名,将首字母大写....");
        return "set" + StringUtils.capitalize(propertyName);
    }
    
    /**
     * 调用newInstance方法，转换非RuntimeException
     * @param clazz
     * @return
     */
    public static Object newInstance(Class clazz) {
        Assert.notNull(clazz);
        try {
            return clazz.newInstance();
        } catch (InstantiationException ex) {
            ex.printStackTrace();
            throw new IllegalArgumentException(ex.getMessage());
        } catch (IllegalAccessException ex) {
            ex.printStackTrace();
            throw new IllegalArgumentException(ex.getMessage());
        }
    }
    
   
	
}
